package cwb
import scala.collection.mutable.HashMap

trait CommonCommand {
  val name: String
  def apply(input: String): Unit
}


trait Commands[+T <: CommonCommand] {
  def commandLine: String

  protected var commandMap = new HashMap[String, CommonCommand]
  protected def notFound(command: String) = println("Command not found: " + command +
      ". Try \"help commands\" for a full list of supported commands")
  

    /**
     * registerCommands adds the given commands to this commands object.
     * @param commands commands to be registered in this commands objects.
     */
    def registerCommands(commands: Collection[CommonCommand]) {
      for (command <- commands) {
        cwb.dbprintln("Registering command " + command.name)
        commandMap.put(command.name, command)
    }
  }
  
  /**
   * Displays the commands defined in this commands object.
   */
  def showAvailableCommands()
  
  def indentPrint(input: String) {
    input.split('\n') foreach(
        line => println("  " + line))
  }
  
  /**
   * getCommand returns the command of the associated name
   * @param name name of the command to be retrieved.
   * @returns the command if it exists and None otherwise.
   */
  def getCommand(name: String) = commandMap.get(name)
  
  /**
   * commandParams splits the given input into command and parameters.
   * @param input the input to be separated
   * @return (command, parameters)
   */
  protected def commandParams(input: String): (String, String) = {
    input.find(c => c == ' '  || c == '(') match {
      case Some(x) => splitByDelim(input, x)
      case None => splitByDelim(input, ' ')
    }
  }
  
  /**
   * runCommand parses the input into command and parameters and executes the
   * given command if it exists or reports an error otherwise.
   * @param input the command input to be executed
   */
  def runCommand(input: String) = {
    val (commandName, params) = commandParams(input)
    commandMap.get(commandName) match {
      case Some(command) => command(params)
      case None => println("Command not found " + commandName)  
    }
  }
  
  
  /**
   * splitByDelim splits the given string by the delimitre and clears initial whitespace.
   * E.g.
   * Splits string "  command<delim>param1 param2 param3" to ("command", " param1 param2 param3")
   * @param input input to be split
   * @delim delimiting character
   * @return (before delim, after delim)
   */
  protected def splitByDelim(input: String, delim: Char): (String, String) = { 
    // Remove all initial/hanging whitespace/newline chars
    var clearIn = input.dropWhile(c => c == ' ' || c == '\n')
    clearIn = clearIn.dropWhile(c => c == ' ' || c == '\n')
    val splitPos = clearIn.indexOf(delim)
    // Split if there is a possibility to.
    if (splitPos != -1) clearIn.splitAt(splitPos) else (clearIn, "")
  }
}